/*******************************************************************************
 * Copyright (c) 2011 Irineu Martins de Lima Moura (imlm2).
 * This file is part of JBeat.
 * 
 *     JBeat is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     JBeat is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with JBeat.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Irineu Martins de Lima Moura (imlm2) - initial API and implementation
 ******************************************************************************/
package br.ufpe.cin.imlm2.util;

import java.util.*;

import br.ufpe.cin.imlm2.jbeat.soot.common.NoSuchOptionException;

public class OptionsParser extends Options {

	private OptionsParser() {
		super();
	}

	public static final String PARAM_PREFIX = "--";
	public static final String SOOT_ARGUMENT_PREFIX = "-";
	public static final String ARGUMENT_SEPARATOR = ":";

	/*
	 * Parameters representations
	 */

	public static final String SHOW_USAGE_PARAM = "help";

	public static final String HANDLE_INSPECTION_PARAM = "handlerInspection";
	public static final String CALL_GRAPH_PARAM = "callGraph";
	public static final String EXCLUDE_REFLECTION_PARAM = "excludeReflection";
	public static final String RUNTIME_EXCEPTIONS_PARAM = "runtimeExceptions";
	public static final String ANALYZE_STANDARD_LIBRARIES_PARAM = "analyzeStdLibs";
	public static final String STATIC_INITIALIZERS_PARAM = "staticInitializers";
	public static final String SYNTHETIC_METHODS_PARAM = "syntheticMethods";

	public static final String SINGLE_FILE_PARAM = "singleFile";
	public static final String FULL_REPORT_PARAM = "fullReport";
	public static final String REPORT_PATH_PARAM = "reportPath";
	public static final String REPORT_CLASSES_PARAM = "reportClasses";
	public static final String REPORT_STANDARD_LIBRARIES_PARAM = "reportStdLibs";
	public static final String CLASS_PATH_PARAM = "classPath";

	/*
	 * Boolean Parameters
	 */
	private boolean __fullReport = false;
	private boolean __singleFile = false;
	private boolean showUsage = false;
	private boolean __handlerInspection = true;
	private boolean __runtimeExceptions = true;
	private boolean __analyzeStdLibs = true;
	private boolean __staticInitializers = false;
	private boolean __reportStdLibs = false;
	private boolean __syntheticMethods = false;
	private boolean __excludeReflection = false;
	private boolean __verbose = false;
	private boolean __time = false;

	/*
	 * Single String parameters
	 */
	private String __callGraph = "cha";
	private String __reportPath = "reports";
	private String mainClass = "";

	/*
	 * String list parameters
	 */

	private List<String> __sreportClasses = new ArrayList<String>();
	private List<String> __sclassPath = new ArrayList<String>();

	private static OptionsParser INSTANCE;

	public static OptionsParser getInstance() {
		if (INSTANCE == null)
			INSTANCE = new OptionsParser();
		return INSTANCE;
	}

	public boolean isHandlerInspection() {
		return __handlerInspection;
	}

	public void setHandlerInspection(boolean withTrapInspection) {
		__handlerInspection = withTrapInspection;
	}

	public String getCallGraph() {
		return __callGraph;
	}

	public void setCallGraph(String call_graph) {
		__callGraph = call_graph;
	}

	public boolean isSingleFile() {
		return __singleFile;
	}

	public void setSingleFile(boolean singleFile) {
		this.__singleFile = singleFile;
	}

	public boolean isFullReport() {
		return __fullReport;
	}

	public void setFullReport(boolean fullReport) {
		this.__fullReport = fullReport;
	}

	public boolean isShowUsage() {
		return showUsage;
	}

	public void setShowUsage(boolean showUsage) {
		this.showUsage = showUsage;
	}

	public String getReportPath() {
		return __reportPath;
	}

	public void setReportPath(String reportPath) {
		this.__reportPath = reportPath;
	}

	public void setAnalyzeRuntime(boolean analyzeRuntime) {
		__runtimeExceptions = analyzeRuntime;
	}

	public boolean isAnalyzeRuntime() {
		return __runtimeExceptions;
	}

	public List<String> getClassReportIncludeList() {
		return __sreportClasses;
	}

	public void setClassReportIncludeList(List<String> classReportIncludeList) {
		__sreportClasses = classReportIncludeList;
	}

	public boolean isReportStandardLibraries() {
		return __reportStdLibs;
	}

	public void setReportStandardLibraries(boolean reportRuntimeLibraries) {
		__reportStdLibs = reportRuntimeLibraries;
	}

	public boolean isAnalyzeStandardLibraries() {
		return __analyzeStdLibs;
	}

	public void setAnalyzeStandardLibraries(boolean analyzeStandardLibraries) {
		__analyzeStdLibs = analyzeStandardLibraries;
	}

	public boolean isStaticInitializers() {
		return __staticInitializers;
	}

	public void setStaticInitializers(boolean staticInitializers) {
		this.__staticInitializers = staticInitializers;
	}

	public boolean isAutoGenerated() {
		return __syntheticMethods;
	}

	public void setAutoGenerated(boolean autoGenerated) {
		__syntheticMethods = autoGenerated;
	}

	public boolean isExcludeReflection() {
		return __excludeReflection;
	}

	public void setExcludeReflection(boolean excludeReflection) {
		this.__excludeReflection = excludeReflection;
	}

	public List<String> getClasspath() {
		return __sclassPath;
	}

	public void setClasspath(List<String> classpath) {
		__sclassPath = classpath;
	}

	public String getMainClass() {
		return mainClass;
	}

	public void setMainClass(String mainClass) {
		this.mainClass = mainClass;
	}

	public boolean isVerbose() {
		return this.__verbose;
	}

	public boolean isTime() {
		return this.__time;
	}

	public void parse(String[] args) throws ParsingException {
		List<String> argsList = new ArrayList<String>(Arrays.asList(args));
		String firstArg = argsList.get(0);
		if (firstArg.equals((OptionsParser.PARAM_PREFIX + SHOW_USAGE_PARAM))) {
			setShowUsage(true);
			return;
		}
		setMainClass(firstArg);
		argsList.remove(0);
		Map<String, String> options = new HashMap<String, String>();
		for (String str : argsList) {

			if (str.startsWith(PARAM_PREFIX)) {
				str = str.replaceFirst(PARAM_PREFIX, "");
				String[] parts = str.split(ARGUMENT_SEPARATOR, 2);
				if (parts.length != 2)
					throw new ParsingException("Unable to parse token: " + str);
				options.put(parts[0], parts[1]);
			} else
				throw new ParsingException("Unable to parse token: " + str);

		}

		try {
			this.parse(options);
		} catch (NoSuchOptionException e) {
			throw new ParsingException("Unkown argument " + e.getInvalidOtion());
		}

	}

}
